package com.itzhanghada.rebitmq.aspect;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itzhanghada.rebitmq.domin.vo.TransactionRecord;
import com.itzhanghada.rebitmq.enums.TransactionStatus;
import com.itzhanghada.rebitmq.mq.MessageSender;
import com.itzhanghada.rebitmq.redis.RedisStorageService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Aspect
@Component
public class RebitTransactionAspect {
    private static final Logger logger = LoggerFactory.getLogger(RebitTransactionAspect.class);

    @Autowired
    private RedisStorageService storageService;

    @Autowired
    private MessageSender messageSender;

    @Around("@annotation(rebitTransactional)")
    public Object executeInTransaction(ProceedingJoinPoint joinPoint, RebitTransactional rebitTransactional) throws Throwable {
        // 生成事务ID
        String txId = generateTxId();

        // 获取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();

        // 创建事务记录
        TransactionRecord record = new TransactionRecord();
        record.setTxId(txId);
        record.setStatus(TransactionStatus.PREPARED);
        record.setCreateTime(System.currentTimeMillis());
        record.setUpdateTime(System.currentTimeMillis());
        record.setRetryCount(0);
        record.setMaxRetry(rebitTransactional.maxRetry());
        record.setExchange(rebitTransactional.exchange());
        record.setRoutingKey(rebitTransactional.routingKey());
        record.setServiceName(rebitTransactional.serviceName());
        record.setClassName(className);
        record.setMethodName(methodName);

        // 序列化参数为消息体
        record.setBody(serializeArguments(joinPoint.getArgs()));

        // 保存事务记录
        storageService.saveTransactionRecord(record);

        try {
            // 执行业务方法
            Object result = joinPoint.proceed();

            // 业务执行成功，更新状态为COMMITTED
            storageService.updateTransactionStatus(txId, TransactionStatus.COMMITTED);

            // 发送消息
            messageSender.sendMessage(record);

            return result;
        } catch (Throwable ex) {
            // 业务执行失败，更新状态为ROLLBACKED
            storageService.updateTransactionStatus(txId, TransactionStatus.ROLLBACKED);
            logger.error("Transaction execution failed, txId: {}", txId, ex);
            throw ex;
        }
    }

    private String generateTxId() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    private String serializeArguments(Object[] args) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(args);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Failed to serialize method arguments", e);
        }
    }
}